module.exports = {
    name: 'cocos',
    des: ``,
    tip: `搜索时最好排除以下文件: *.meta, temp, *.fire, library`,
    contents: [
        {
            keyWord: `cc.director`,
            des: `导演类`
        },
        {
            keyWord: `_decorator`,
            des: `一些 JavaScript 装饰器，目前可以通过 "cc._decorator" 来访问`,
            list: [
                {
                    keyWord: `executeInEditMode`,
                    des: `允许继承自 Component 的 CCClass 在编辑器里执行`
                },
                {
                    keyWord: `executionOrder`,
                    des: `节点有多个组件时,设置组件脚本生命周期方法调用的优先级。优先级小于 0 的组件将会优先执行，优先级大于 0 的组件将会延后执行`
                }
            ]
        },
        {
            keyWord: `事件`,
            des: ``,
            exp: `事件类型
            const { TOUCH_START } = cc.Node.EventType;
            const { KEY_DOWN } = cc.SystemEvent.EventType;
            
            TOUCH_CANCEL // 当手指在目标节点区域外离开屏幕时触发`,
            list: [
                {
                    keyWord: `系统事件`,
                    exp: `
                    const { TOUCH_START } = cc.Node.EventType;
                    const { KEY_DOWN } = cc.SystemEvent.EventType;
                    this.node.on(TOUCH_START, this.onStartHandler, this)
                    cc.systemEvent.on(KEY_DOWN, this.onKeyDownHandler, this);`
                },
                {
                    keyWord: `自定义事件`,
                    exp: `const ON_FIRE = 'onfire'
                    this.node.on(ON_FIRE, function(msg){
                        console.log(msg)
                    })
                    const msgFordispatchEvent = new cc.Event.EventCustom(ON_FIRE, true) // true表示向上传递
                    msgFordispatchEvent.detail = 'bbb'
                    // this.node.emit(ON_FIRE, 'aaa')
                    this.node.dispatchEvent(msgFordispatchEvent) // 可以向上传递事件`
                },
                {
                    keyWord: `同级节点间的触点归属问题`,
                    des: `假设上图中 B、C 为同级节点，C 节点部分覆盖在 B 节点之上。这时候如果 C 节点接收到触摸事件后，就宣布了触点归属于 C 节点，这意味着同级节点的 B 就不会再接收到触摸事件了，即使触点同时也在 B 节点内。同级节点间，触点归属于处于顶层的节点`
                }
            ],
            tip: ``
        },
        {
            keyWord: `定时器`,
            exp: `this.schedule(this.timerHandler, this.ducretion) // 开启
            this.unschedule(this.timerHandler) // 关闭`
        },
        {
            keyWord: `资源`,
            list: [
                {
                    keyWord: `cc.resources.load('路径', 类型, fn)`,
                    des: `动态加载资源`,
                    tip: `动态资源必须放在assets/resources目录下面`
                },
                {
                    keyWord: `cc.resources.loadDir('路径', 类型, fn)`,
                    des: `加载一组资源`
                },
                {
                    keyWord: `预制资源`,
                    des: `对于项目中会重复生成的节点，使用预制件是很有必要的
                    在场景中将节点编辑好之后，直接将节点从 层级管理器 拖到 资源管理器 中即可完成预制件的创建。
                    完成创建后，原节点自动变为该预制件节点，呈现 绿色`
                }
            ]
        },
        {
            keyWord: `字体资源`,
            des: `系统字体，动态字体，位图字体`
        },
        {
            keyWord: `粒子资源`,
            des: ``
        },
        {
            keyWord: `tiledMap地图`,
            des: ``
        },
        {
            keyWord: `spine 骨骼动画`,
            des: `//类型：sp.Skeleton
            this.ske_anim.clearTracks()//清空所有播放管道动画
            this.ske_anim.clearTrack(0)//清空指定索引管道动画
            this.ske_anim.setAnimation(0,'animation_1',false)//清空管道动画，播放animation_1动画
            this.ske_anim.addAnimation(0,'animation_2',false)//将animation_1动画添加到管道里，依次播放`
        },
        {
            keyWord: `生命周期`,
            des: `onLoad
            onEnable 激活
            start
            update(dt)  每秒60帧（每16毫秒执行一次） dt就是两帧直间的间隔时间单位是秒大概是0.016秒(1千毫秒==1秒)
            lateUpdate 在动效更新/update之后执行
            onDisable 禁用
            onDestroy`
        },
        {
            keyWord: `节点操作`,
            des: ``,
            list: [
                {
                    keyWord: `this.node`,
                    des: `当前节点`
                },
                {
                    keyWord: `this.node.getComponent(cc.Label)`,
                    des: `查找当前节点下的系统组件`
                },
                {
                    keyWord: `this.node.getChildByName('Btn')`,
                    des: `查找当前节点下的直属自定义子节点`
                },
                {
                    keyWord: `cc.find('Box/btn', this.node)`,
                    des: `查找当前节点下的子孙节点
                    第二个参数默认是根节点`
                },
                {
                    keyWord: `this.node.parent`,
                    des: `父节点`
                },
                {
                    keyWord: `addChild`,
                    des: `添加节点`,
                    exp: `const contaner = cc.find('Canvas')
                    this.node.removeFromParent(false)
                    contaner.addChild(this.node)
                    或
                    this.node.parent = contaner`,
                    tip: `removeFromParent通常需要传入false，否则默认会清空节点上的事件和action`
                },
                {
                    keyWord: `new cc.Node()`,
                    des: `创建节点
                    新节点创建后，要为其设置一个父节点才能完成节点的初始化`
                },
                {
                    keyWord: `this.node.addComponent(cc.Sprite)`,
                    des: `为节点添加组件，返回组件实例`,
                    exp: `// 添加脚本组件
                    let script: BulletScript = bnode.addComponent( BulletScript ) // BulletScript：自定义的script类
                    script.explodeEffect = this.explodeEffect;`
                },
                {
                    keyWord: `this.node.childrenCount`,
                    des: `当前子节点数量`
                },
                {
                    keyWord: `this.node.setPosition`,
                    des: `设置位置`
                },
                {
                    keyWord: `this.node.setRotation`,
                    des: `设置旋转`
                },
                {
                    keyWord: `this.node.setScale`,
                    des: `设置缩放`
                },
                {
                    keyWord: `this.node.setContentSize`,
                    des: `设置宽高大小`
                },
                {
                    keyWord: `this.node.setAnchorPoint`,
                    des: `设置节点锚点位置
                    锚点默认位置是 (0.5 0.5) 即中心点
                    可以设置锚点超出节点本身的大小`
                },
                {
                    keyWord: `this.node.setSiblingIndex()`,
                    des: `设置节点的层级级别`
                },
                {
                    keyWord: `cc.instantiate( 节点 )`,
                    des: `克隆节点`
                },
                {
                    keyWord: `this.node.destroy() / this.node.removeFromParent()`,
                    des: `销毁节点`
                }
            ]
        },
        {
            keyWord: `场景`,
            des: `引擎同时只能运行一个场景，如果需要用一个组件控制所有场景的切换或传参，就需要设置常驻节点`,
            list: [
                {
                    keyWord: `cc.director.loadScene('xxx', fn)`,
                    des: `加载场景`
                },
                {
                    keyWord: `cc.director.preloadScene('xxx',progressFn, fn)`,
                    des: `预加载场景`
                },
                {
                    keyWord: `cc.game.addPersistRootNode(this.node)`,
                    des: `设置常驻节点
                    目标节点必须为位于层级的根节点`
                },
                {
                    keyWord: `cc.game.removePersistRootNode(this.node)`,
                    des: `取消常驻节点`
                }
            ]
        },
        {
            keyWord: `动作系统`,
            list: [
                {
                    keyWord: `基本移动`,
                    exp: `let action = cc.moveTo(2, 100, 100) // 声明一个动作,移动到100，100的位置
                    this.node.runAction(action) // 执行一个动作, 过时的api
                    this.node.stopAction(action) // 停止一个动作
                    this.node.stopAllActions() // 停止所有动作`
                },
                {
                    keyWord: `let action = cc.moveBy(2, 100, 100)`,
                    des: `相对当前的位置，累加移动`
                },
                {
                    keyWord: `容器动作`,
                    exp: `cc.sequence(actions) 顺序运动
                    cc.spawn(actions) 同步运动
                    cc.repeat(actions, 重复次数) 重复运动
                    cc.repeatForever(actions) 永远重复
                    cc.callFunc()  动作回调`
                },
                {
                    keyWord: `tween`,
                    des: `新的动作方式`,
                    exp: `cc.tween(peiqinode)
                    .by(0.5, {position: cc.v3(0, -h, 0)}, {easing: 'quadIn'})
                    .by(0.2, {position: cc.v3(0, h / 6, 0)}, {easing: 'quadOut'})
                    .by(0.2, {position: cc.v3(0, -(h / 6), 0)}, {easing: 'quadIn'})
                    .start()`
                }
            ]
        },
        {
            keyWord: `ui系统/图像/渲染`,
            list: [
                {
                    keyWord: `Sprite`,
                    des: `精灵组件
                    Atlas 图集资源
                    Sprite 图片资源
                    Type 渲染模式
                    Size Mode 裁剪模式`
                },
                {
                    keyWord: `Label`,
                    des: `文字`
                },
                {
                    keyWord: `Button`,
                    des: `按钮
                    Click Events 设置点击事件关联到其他节点或根节点的函数，使点击按钮时能够直接调用其他节点的函数，参数会传到第二个形参上
                    Transiton 所有效果可以混合设置
                        选Sprite设置按钮点击效果，可设置hover、disabled、pressed的图片
                        选Color设置颜色
                        选Scale设置点击是否有缩放效果
                    `
                },
                {
                    keyWord: `Widget`,
                    des: `可定义父级的上下左右的边界值，以达到宽高的自动适配`
                },
                {
                    keyWord: `Animation`,
                    des: `动画编辑器
                    1添加Animation组件
                    2新建Clip文件
                    3添加property
                    4设置时间和效果
                    ctrl/command + left 跳到第0帧
                    ctrl/command + right 跳到最后一帧
                    点击场景中的虚线，即可编辑bebe
                    如果想要动画在屏幕中停留一会，则可以设置两个关键帧中间为空`,
                    exp: `const a = this.node.getComponent(cc.Animation) // 获取Animation实例
                    a.play() // 播放
                    a.stop() // 停止
                    a.pause() // 暂停
                    a.resume() // 恢复播放
                    ...`
                },
                {
                    keyWord: `Mask`,
                    des: `蒙版组件
                    RECT 规则矩形
                    ELLIPSE 圆或椭圆
                    IMAGE_STENCIL 根据图片生成不规则图形`
                },
                {
                    keyWord: `屏幕适配`,
                    des: `常见的分辨率
                    16:9 1920*1080，1280*720，960*540，640*360
                    3:2 1200*900，960*640
                    全面屏手机的分辨率要比16:9长一些
                    
                    竖屏设置
                    1 修改Canvas大小，如：720*1280
                    2 修改Main Camera 的Size为Canvas的大小，如果勾选Align With Screen后也可以设置Size为0*0
                    3 设置模拟器为竖屏显示`,
                    exp: `根据分辨率的实际宽度动态适配：
                    const pixels = cc.director.getWinSizeInPixels();
                    const uiWidth = 720  // 设计稿的宽度;
                    const scaleW = pixels.width / uiWidth // 分辨率和设计稿之间的比例;
                    全局节点.scale = scaleW
                    const scaleW2 = uiWidth / 节点.width // 设计稿和节点的比例
                    节点.scale = scaleW * scaleW2 // 设置节点的宽度占满全屏的宽度`
                },
                {
                    keyWord: `Graphics 组件`,
                    des: `自定义绘制图形/多边形/三角形/自定义渲染类组件, 类似与canvas的绘制，api都差不多`
                },
                {
                    keyWord: `BlockInputEvents`,
                    des: `BlockInputEvents 组件将拦截所属节点 bounding box 内的所有输入事件（鼠标和触摸），防止输入穿透到下层节点，一般用于上层 UI 的背景
                    该组件没有任何 API 接口，直接添加到场景即可生效`
                },
                {
                    keyWord: `Layout`,
                    des: `Layout 是一种容器组件，容器能够开启自动布局功能，自动按照规范排列所有子物体，方便用户制作列表、翻页等功能`
                },
                {
                    keyWord: `ScrollView`,
                    des: `ScrollView 是一种带滚动功能的容器，它提供一种方式可以在有限的显示区域内浏览更多的内容`
                },
                {
                    keyWord: `ProgressBar`,
                    des: `进度条组件,经常被用于在游戏中显示某个操作的进度`
                }
            ]
        },
        {
            keyWord: `声音与音效`,
            des: `音乐Miusc，一般使用 Audio Source组件播放
            音效Audio、配音Voice，一般使用cc.audioEngine.play()播放
            `,
            exp: `const audio = cc.audioEngine.play(音频资源, 是否循环播放, 音量)//播放
            cc.audioEngine.setFinishCallback(audio, function(){})//监听某个audio播放完毕`
        },
        {
            keyWord: `碰撞检测`,
            des: `BoxCollider 矩形碰撞
            CircleCollider 圆形碰撞
            PolygonCollider 多边形碰撞`,
            exp: `
            // 开启碰撞检测全局对象，只需在全局入口开启即可
            var manager = cc.director.getCollisionManager();
            manager.enabled = true;
            manager.enabledDebugDraw = true; // 开启调试`,
            list: [
                {
                    keyWord: `产生碰撞`,
                    exp: `onCollisionEnter: function (other, self) {
                        // 碰撞系统会计算出碰撞组件在世界坐标系下的相关的值，并放到 world 这个属性里面
                        var world = self.world;
                    
                        // 碰撞组件的 aabb 碰撞框
                        var aabb = world.aabb;
                    
                        // 节点碰撞前上一帧 aabb 碰撞框的位置
                        var preAabb = world.preAabb;
                    
                        // 碰撞框的世界矩阵
                        var t = world.transform;
                    
                        // 以下属性为圆形碰撞组件特有属性
                        var r = world.radius;
                        var p = world.position;
                    
                        // 以下属性为 矩形 和 多边形 碰撞组件特有属性
                        var ps = world.points;
                    }`
                },
                {
                    keyWord: `碰撞产生后，碰撞结束前`,
                    exp: `onCollisionStay: function (other, self) {}`
                },
                {
                    keyWord: `碰撞结束后`,
                    exp: `onCollisionExit: function (other, self) {}`
                }
            ]
        },
        {
            keyWord: `物理系统`,
            des: `Restitution 弹性系数`,
            list: [
                {
                    keyWord: `开启物理系统`,
                    exp: `cc.director.getPhysicsManager().enabled = true; // 只需在全局入口开启即可`
                },
                {
                    keyWord: `常用属性`,
                    des: `cc.RigidBodyType.Static
                    静态刚体，零质量，零速度，即不会受到重力或速度影响，但是可以设置他的位置来进行移动。
                    
                    cc.RigidBodyType.Dynamic
                    动态刚体，有质量，可以设置速度，会受到重力影响。
                    
                    cc.RigidBodyType.Kinematic
                    运动刚体，零质量，可以设置速度，不会受到重力的影响，但是可以设置速度来进行移动。
                    
                    cc.RigidBodyType.Animated
                    动画刚体，在上面已经提到过，从 Kinematic 衍生的类型，主要用于刚体与动画编辑结合使用。`
                },
                {
                    keyWord: `刚体碰撞回调`,
                    exp: `// 只在两个碰撞体开始接触时被调用
                    onBeginContact: function (contact, selfCollider, otherCollider) {
                        contact 中，这是一个 cc.PhysicsContact 类型的实例，可以在 api 文档中找到相关的 API。
                        contact 中比较常用的信息就是碰撞的位置和法向量，contact 内部是按照刚体的本地坐标来存储信息的，而我们一般需要的是世界坐标系下的信息，我们可以通过 
                        contact.getWorldManifold 来获取这些信息
                    },
                
                    // 只在两个碰撞体结束接触时被调用
                    onEndContact: function (contact, selfCollider, otherCollider) {},
                
                    // 每次将要处理碰撞体接触逻辑时被调用
                    onPreSolve: function (contact, selfCollider, otherCollider) {},
                
                    // 每次处理完碰撞体接触逻辑时被调用
                    onPostSolve: function (contact, selfCollider, otherCollider) {}`
                },
                {
                    keyWord: `力与冲量`,
                    des: `移动一个物体有两种方式，可以施加一个力或者冲量到这个物体上。力会随着时间慢慢修改物体的速度，而冲量会立即修改物体的速度。
                    当然你也可以直接修改物体的位置，只是这看起来不像真实的物理，你应该尽量去使用力或者冲量来移动刚体，这会减少可能带来的奇怪问题`,
                    exp: `// 施加一个力到刚体上指定的点上，这个点是世界坐标系下的一个点
                    rigidbody.applyForce(force, point);
                    
                    // 或者直接施加力到刚体的质心上
                    rigidbody.applyForceToCenter(force);
                    
                    // 施加一个冲量到刚体上指定的点上，这个点是世界坐标系下的一个点
                    rigidbody.applyLinearImpulse(impulse, point);`
                }
            ]
        },
        {
            keyWord: `cc.Color()`,
            des: `生成颜色值`,
            exp: `g.fillColor = new cc.Color().fromHEX('#ffff00'); // 设置填充颜色`
        },
        {
            keyWord: `js脚本`,
            list: [
                {
                    keyWord: `打开外部网址`,
                    des: `cc.sys.openURL("http://www.baidu.com")`
                }
            ]
        },
        {
            keyWord: `向量和坐标`,
            list: [
                {
                    keyWord: `Vec2`,
                    des: `2d向量`,
                    exp: `v.sub(cc.v2(5, 5));  //向量减法
                    v.sub(cc.v2(5, 5)).mag() // 计算两个的距离,(mag返回向量的长度)`
                },
                {
                    keyWord: `Vec3`,
                    des: `3D 向量和坐标`
                },
                {
                    keyWord: `两个节点的坐标转换`,
                    exp: `const pos = node1.convertToWorldSpaceAR(cc.v3(0,0,0))//获取节点1的世界坐标
                    const disPos = tagNode.convertToNodeSpaceAR(pos) // 节点2依据节点1的世界坐标，得出节点2坐标和节点1的坐标差值
                    const tagOrigPos = tagNode.position() // 获取节点2当前的坐标
                    const resPos = tagOrigPos.add(disPos) // 计算节点2在自己的父级中对应节点1位置的坐标
                    tagNode.setPosition(resPos)`
                }
            ]
        },
        {
            keyWord: `JSB`,
            des: `从 JS 端直接调用 Native 端（Android/iOS/Mac）的接口`,
            exp: `if(cc.sys.isNative && cc.sys.os == cc.sys.OS_IOS) {
                jsb.reflection.callStaticMethod('ABCFileDownloader', 'downloadFileWithUrl:cookie:savePath:', url, cookies, savePath);
            } else if(cc.sys.isNative && cc.sys.os == cc.sys.OS_ANDROID) {
                jsb.reflection.callStaticMethod("com/tencent/abcmouse/downloader/ABCFileDownloader", "方法名", "(参数)V", url, cookies, savePath);
                jsb.reflection.callStaticMethod("打包android项目后app/src目录下的文件路径", "方法名", "(参数)V", url, cookies, savePath);
            }`,
            tip: `另外有一点需要注意的就是，在 Android 应用中，Cocos 引擎的渲染和 JS 的逻辑是在 GL 线程中进行的，而 Android 本身的 UI 更新是在 App 的 UI 线程进行的，所以如果我们在 JS 中调用的 Java 方法有任何刷新 UI 的操作，都需要在 UI 线程进行`
        },
        {
            keyWord: `原生执行 JavaScript 代码`,
            exp: ` C++ / Objective-C:
            Application::getInstance()->getScheduler()->performFunctionInCocosThread([=](){
                se::ScriptEngine::getInstance()->evalString(script.c_str());
            });
            java:
            Cocos2dxJavascriptJavaBridge.evalString("cc.__myGlobal.game.testFn('params')");
            //cc.__myGlobal可以是自定义的任意的cocos的全局变量
            final String jsCallstr = String.format("cc.__myGlobal.game.testFn('%s')", params) // java拼接字符串的方式
            Cocos2dxJavascriptJavaBridge.evalString(jsCallstr);`
        }
    ]
}